package nc.bs.gl.hrpbctprule.util;

import nc.bs.framework.common.NCLocator;
import nc.bs.gl.eventlistener.bmcontrol.AggBmCtrlVoucherVO;
import nc.bs.gl.eventlistener.bmcontrol.BmCtrlVoucherVOGenerator;
import nc.bs.gl.hrpbctprule.constants.GlControlRuleConst;
import nc.bs.gl.hrpbctprule.vo.BmCtrlVoucherVOGeneratorNew;
import nc.codeplatform.framework.commons.DaoUtils;
import nc.itf.hrpbm.budgetctrl.service.IBmBudgetControlService;
import nc.vo.datamapping.datamapping.AggDatamappingMasterVO;
import nc.vo.datamapping.datamapping.DatamappingMasterVO;
import nc.vo.datamapping.datamapping.DatamappingSlave0VO;
import nc.vo.gl.pubvoucher.OperationResultVO;
import nc.vo.gl.pubvoucher.VoucherVO;
import nc.vo.hrpbctp.busibillconfig.AggBusiConfigVO;
import nc.vo.hrpbctp.busibillconfig.BusiConfigVO;
import nc.vo.hrpbm.budgettype.Budgettype;
import nc.vo.pub.BusinessException;
import nc.vo.pubapp.pattern.exception.ExceptionUtils;
import nc.vo.pubapp.pattern.pub.SqlBuilder;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

public class GlControlRuleUtil {
    private static DaoUtils daoUtils = new DaoUtils();

    public static boolean enableGl(String billtype, String transtype, String otherfilter) {

        List<AggBusiConfigVO> configVOS = null;
        try {
            configVOS = queryBusiConfig(billtype, transtype, otherfilter);
        } catch (BusinessException e) {
            ExceptionUtils.wrappBusinessException(e.getMessage());
        }
        if (CollectionUtils.isEmpty(configVOS)) {
            return Boolean.FALSE.booleanValue();
        }
        //这里去判断一下是否启用了总之控制规则,如果启用了,那么收入+支出都得有
        int glControlRuleCount = 0;
        for (AggBusiConfigVO configVO : configVOS) {
            BusiConfigVO parentVO = configVO.getParentVO();
            String filter = parentVO.getOtherfilter();
            if (StringUtils.isEmpty(filter)) {
                continue;
            }
            if ((filter.equals(GlControlRuleConst.SR_DISPLAY) || filter.equals(GlControlRuleConst.ZC_DISPLAY))
                    && parentVO.getEnableglrule() != null && parentVO.getEnableglrule().booleanValue()) {
                glControlRuleCount++;
            }
        }
        if (glControlRuleCount == 1) {
            ExceptionUtils.wrappBusinessException("业务单据配置单据类型为总账凭证时,则支出和收入数据需同时开启或同时关闭[是否启用总账业务规则]");
        }
        return glControlRuleCount == 2 ? Boolean.TRUE.booleanValue() : Boolean.FALSE.booleanValue();
    }

    public static boolean enableGl(String billtype, String transtype) {
        return enableGl(billtype, transtype, null);
    }

    public static List<AggBusiConfigVO> queryBusiConfig(String billtype, String transtype, String otherfilter) throws BusinessException {
        /*
         * 基础检查
         * 单据类型不能为空，参数vo不能为空
         */
        if (billtype == null || "".contentEquals(billtype))
            throw new BusinessException("参数错误：\n单据类型不能为空！");

        /*
         * 查询业务单据配置信息
         * 初步检查业务单据配置信息
         */
        AggBusiConfigVO[] billSettingVos = BctpControlBsUtils.queryBusiConfig(billtype, transtype, otherfilter);
        return ArrayUtils.isEmpty(billSettingVos)? Collections.EMPTY_LIST: Arrays.stream(billSettingVos).toList();

    }

    public static List<OperationResultVO> processBudgetControl(String actionCode, VoucherVO voucher, VoucherVO oldVoucher) {

        List<OperationResultVO> results = new ArrayList<OperationResultVO>();

        try {
            BmCtrlVoucherVOGeneratorNew ctrlvoGenerator = new BmCtrlVoucherVOGeneratorNew();
            Map<String, Object> bmCtrlVOMap = ctrlvoGenerator.generateBmCtrlVO(voucher);
            Map<String, Object> oldbmCtrlVOMap = ctrlvoGenerator.generateBmCtrlVO(oldVoucher);
            for (String topBudgetCode : bmCtrlVOMap.keySet()) {
                AggBmCtrlVoucherVO ctrlAggVo = bmCtrlVOMap.get(topBudgetCode) == null ? null : (AggBmCtrlVoucherVO) bmCtrlVOMap.get(topBudgetCode);
                AggBmCtrlVoucherVO oldCtrlAggVo = oldbmCtrlVOMap.get(topBudgetCode) == null ? null : (AggBmCtrlVoucherVO) oldbmCtrlVOMap.get(topBudgetCode);
                if (ctrlAggVo == null && oldCtrlAggVo == null) {
                    continue;
                }
                if (ctrlAggVo == null && oldCtrlAggVo != null) {
                    ctrlAggVo = new AggBmCtrlVoucherVO();
                    ctrlAggVo.setParentVO(oldCtrlAggVo.getParentVO());
                }
                if (ctrlAggVo != null) {
                    String otherfilter = getOtherfilter(ctrlAggVo.getParentVO().getSztype());
                    if (StringUtils.isEmpty(otherfilter)) {
                        continue;
                    }
                    OperationResultVO result = budgetCtrl(topBudgetCode, otherfilter, actionCode, voucher, ctrlAggVo, oldCtrlAggVo);

                    if(result != null){
                        results.add(result);
                    }

                }
            }

        } catch (Exception e) {
            ExceptionUtils.wrappBusinessException(e.getMessage());
        }

        return results;
    }

    public static String getOtherfilter(String sztype) {
        if (StringUtils.isEmpty(sztype)) {
            return null;
        }
        if (sztype.equals(GlControlRuleConst.SR)) {
            return GlControlRuleConst.SR_DISPLAY;
        }
        if (sztype.equals(GlControlRuleConst.ZC)) {
            return GlControlRuleConst.ZC_DISPLAY;
        }
        return null;
    }


    public static OperationResultVO budgetCtrl(String topBudgetCode, String otherFilter, String actionCode, VoucherVO voucher, AggBmCtrlVoucherVO ctrlAggVo, AggBmCtrlVoucherVO oldCtrlAggVo) throws BusinessException {

        if (ctrlAggVo != null || oldCtrlAggVo != null) {

            NCLocator.getInstance().lookup(IBmBudgetControlService.class).budgetControl(ctrlAggVo.getParentVO().getPk_group(),
                    ctrlAggVo.getParentVO().getPk_org(), GlControlRuleConst.BILLTYPE, null, otherFilter, actionCode, ctrlAggVo, oldCtrlAggVo, new String[]{topBudgetCode});

            return BmCtrlVoucherVOGenerator.getBmCtrlResult(ctrlAggVo, voucher);

        }
        return new OperationResultVO();

    }

    public static Map<String, Map<String, String>> getDataMapping(VoucherVO voucher, String accountversion) {
        if (voucher == null) {
            return Collections.EMPTY_MAP;
        }
        AggDatamappingMasterVO[] masterVOS = getDataMappings(voucher, accountversion);
        Map<String, Map<String, String>> map = new HashMap<>();
        if (ArrayUtils.isNotEmpty(masterVOS)) {
            for (AggDatamappingMasterVO masterVO : masterVOS) {
                DatamappingMasterVO parentVO = masterVO.getParentVO();
                String buildKey = buildKey(parentVO);
                DatamappingSlave0VO[] childrenVO = (DatamappingSlave0VO[]) masterVO.getChildrenVO();
                map.put(buildKey, Collections.EMPTY_MAP);
                if (!ArrayUtils.isEmpty(childrenVO)) {
                    map.put(buildKey, Arrays.stream(childrenVO)
                            .collect(Collectors.toMap(
                                    key -> key.getPk_src(), value -> value.getPk_dest(), (exitValue, newValue) -> exitValue)
                            ));
                }

            }
        }
        return map;
    }

    public static Map<String, Budgettype> getBudgettypes() {
        try {
            Budgettype[] budgettypes = daoUtils.listByCondition(Budgettype.class, null);
            if (ArrayUtils.isNotEmpty(budgettypes)) {
                return Arrays.stream(budgettypes).collect(Collectors.toMap(Budgettype::getPk_budgettype, Budgettype -> Budgettype));
            }
        } catch (BusinessException e) {
            //throw new RuntimeException(e);
        }
        return Collections.EMPTY_MAP;


    }

    public static String buildKey(DatamappingMasterVO paramVO) {
        if (paramVO == null) {
            return null;
        }
        StringBuilder builder = new StringBuilder();
        builder.append(paramVO.getPk_org());
        builder.append(GlControlRuleConst.KEY_SPLIT);
        builder.append(paramVO.getBudget_year());
        builder.append(GlControlRuleConst.KEY_SPLIT);
        builder.append(paramVO.getPk_accassitem());
        builder.append(GlControlRuleConst.KEY_SPLIT);
        builder.append(paramVO.getPk_srcentity());
        builder.append(GlControlRuleConst.KEY_SPLIT);
        builder.append(paramVO.getPk_accountingbook());
        builder.append(GlControlRuleConst.KEY_SPLIT);
        builder.append(paramVO.getAccasoa_version());
        builder.append(GlControlRuleConst.KEY_SPLIT);
        builder.append(paramVO.getPk_ctrl_dim());
        builder.append(GlControlRuleConst.KEY_SPLIT);
        builder.append(paramVO.getPk_destentity());
        return builder.toString();
    }

    public static AggDatamappingMasterVO[] getDataMappings(VoucherVO voucher, String accountversion) {
        SqlBuilder sqlBuilder = new SqlBuilder();
        sqlBuilder.append(DatamappingMasterVO.PK_ORG, voucher.getPk_org());
        sqlBuilder.append(" and ");
        sqlBuilder.append(DatamappingMasterVO.BUDGET_YEAR, voucher.getYear());
//        sqlBuilder.append(" and ");
//        sqlBuilder.append(DatamappingMasterVO.PK_ACCOUNTINGBOOK, voucher.getPk_accountingbook());
//        sqlBuilder.append(" and ");
//        sqlBuilder.append(DatamappingMasterVO.ACCASOA_VERSION, accountversion);
        AggDatamappingMasterVO[] masterVOS = null;
        try {
            masterVOS = daoUtils.listByCondition(AggDatamappingMasterVO.class, sqlBuilder.toString());
        } catch (BusinessException e) {
            //throw new RuntimeException(e);
        }
        return masterVOS;

    }
}
